package com.zyq.intercepter;

import com.zyq.annotation.AccessLimit;
import com.zyq.annotation.PreAuthorize;
import com.zyq.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author xiaochi
 * @date 2021/4/30 17:56
 * @desc
 */
@Slf4j
public class GlobalInterceptor implements HandlerInterceptor {

//    private final String TRACE_ID = "trace_id";

    private final ThreadLocal<Map<String,Long>> mapThreadLocal = ThreadLocal.withInitial(ConcurrentHashMap::new);

    /**
     * 处理请求之前执行（Controller方法调用之前）
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        MDC.put(TRACE_ID, UUID.randomUUID().toString().replace("-",""));
        mapThreadLocal.get().put("startTime",System.currentTimeMillis());
        // 如果报错不能强转 HandlerMethod，是该路由没有排除，被拦截器拦截了，请排除路由就可以了
        if (!(handler instanceof HandlerMethod)){// 静态文件不是方法
            return true;
        }
        HandlerMethod method = (HandlerMethod) handler;
        if (method.hasMethodAnnotation(AccessLimit.class)){
            SpringContextUtils.getBean("accessLimitIntercepter", BaseInterceptor.class).doHandler(request,response,method);
        }
        if (method.hasMethodAnnotation(PreAuthorize.class)){
            SpringContextUtils.getBean("authorizeIntercepter", BaseInterceptor.class).doHandler(request,response,method);
        }
        return true;
    }

    /**
     * 处理请求之后执行，但是在视图被渲染之前（Controller方法调用之后）
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String url = request.getRequestURI();
        /*if (!(handler instanceof HandlerMethod)){// 静态文件不是方法
            log.info("资源访问url出错:{}",url);
        }*/
        HandlerMethod method = (HandlerMethod) handler;
        String classMethodName = method.getBean().getClass() + "." + method.getMethod().getName();
        Long time = System.currentTimeMillis() - mapThreadLocal.get().get("startTime");
        String parameter = this.getParameter(request);
        mapThreadLocal.remove();// 一定要释放掉
        log.info("接口地址[{}],请求方式[{}],时长[{}]毫秒,控制器[{}],参数[{}]",url,request.getMethod(), time,classMethodName,parameter);
    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //MDC.remove(TRACE_ID);
    }

    /**
     * 获取参数(注意：获取不到json参数，只能获取表单参数)
     * @param request
     * @return
     */
    public String getParameter(HttpServletRequest request){
        StringBuilder sb = new StringBuilder(100);
        Enumeration<String> parameteres = request.getParameterNames();
        if (parameteres.hasMoreElements()){
            while (parameteres.hasMoreElements()){
                String key = parameteres.nextElement();
                String[] values = request.getParameterValues(key);
                sb.append(key).append("=");
                for (String val : values){
                    sb.append(val);
                }
                sb.append(",");
            }
        }
        return sb.toString().length() > 0 ? sb.toString().substring(0,sb.length()-1) : "";
    }
}
